
package jaygoo.widget.wlv;

import ohos.agp.components.AttrSet;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.render.Canvas;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Optional;

/**
 * 版    本：1.0.0
 * 封装的SurfaceView
 *
 * @author JayGoo
 * @since 2017-07-21
 */
public abstract class RenderView extends SurfaceProvider implements SurfaceOps.Callback {

    // 是否正在绘制动画
    private boolean isStartAnim = false;
    private static final Object surfaceLock = new Object();
    private RenderThread renderThread;

    /**
     * 构造器
     *
     * @param context
     * @param attrs
     * @noinspection checkstyle:DeclarationOrder
     */
    public RenderView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 构造器
     *
     * @param context
     * @noinspection checkstyle:DeclarationOrder
     */
    public RenderView(Context context) {
        this(context, null);
    }


    /**
     * 构造器
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     * @noinspection checkstyle:DeclarationOrder
     */
    public RenderView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs);
        getSurfaceOps().get().addCallback(this);

    }

    /**
     * 绘制背景，防止开始时黑屏
     * 子View可以执行此方法
     *
     * @param canvas
     */
    protected abstract void doDrawBackground(Canvas canvas);

    /**
     * 渲染surfaceView的回调方法。
     *
     * @param canvas 画布
     * @param millisPassed
     */
    protected abstract void onRender(Canvas canvas, long millisPassed);



    /**
     *
     * 回调/线程
     *
     * @since 2017-07-21
     * */
    private static class RenderThread extends Thread {

        private static final long SLEEP_TIME = 16L;
        private WeakReference<RenderView> renderView;
        private boolean running = false;
        private boolean destoryed = false;
        private boolean isPause = false;

        RenderThread(RenderView renderView) {
            super("RenderThread");
            this.renderView = new WeakReference<>(renderView);
        }

        private SurfaceOps getSurfaceHolder() {
            if (getRenderView() != null) {
                return renderView.get().getSurfaceOps().get();
            }
            return (SurfaceOps) Optional.empty().get();
        }

        private RenderView getRenderView() {
            return renderView.get();
        }

        @Override
        public void run() {
            // e.post
            long startAt = System.currentTimeMillis();
            while (!destoryed) {
                synchronized (surfaceLock) {
                    // 这里并没有真正的结束Thread，防止部分手机连续调用同一Thread出错
                    while (isPause) {
                        try {
                              surfaceLock.wait();
                        } catch (InterruptedException e) {
                            e.getMessage();
                        }
                    }

                    if (running) {
                        if (getSurfaceHolder() != null && getRenderView() != null) {
                            Canvas canvas = getSurfaceHolder().lockCanvas();
                            if (canvas != null) {
                                getRenderView().doDrawBackground(canvas);
                                if (getRenderView().isStartAnim) {
                                    HiLog.info(label, "RV_stopAnim:  4--> " + System.currentTimeMillis());
                                    getRenderView().render(canvas, System.currentTimeMillis() - startAt);  //这里做真正绘制的事情
                                }
                                getSurfaceHolder().unlockCanvasAndPost(canvas);
                            }
                        } else {
                            running = false;
                        }

                    }

                }
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }


        public void setRun(boolean isRun) {
            this.running = isRun;
        }

    }

    /**
     * 解锁暂停，继续执行绘制任务
     * 默认当Resume时不自动启动动画
     */
    public void onResume() {
        synchronized (surfaceLock) {
            if (renderThread != null) {
                renderThread.isPause = false;
                surfaceLock.notifyAll();
            }
        }
    }

    /**
     * 暂停
     **/
    public void onPause() {
        synchronized (surfaceLock) {
            if (renderThread != null) {
                renderThread.isPause = true;
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceOps surfaceOps) {
        HiLog.info(label, "RV_surfaceCreated");
        renderer = onCreateRenderer();
        if (renderer != null && renderer.isEmpty()) {
            throw new IllegalStateException();
        }

        renderThread = new RenderThread(this);
    }

    @Override
    public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) {
        // 这里可以获取SurfaceView的宽高等信息
    }

    @Override
    public void surfaceDestroyed(SurfaceOps surfaceOps) {
        synchronized (surfaceLock) { //这里需要加锁，否则doDraw中有可能会crash
            renderThread.setRun(false);
            renderThread.destoryed = true;
        }
    }

    public void onWindowFocusChanged(boolean hasFocus) {
        if (hasFocus && isStartAnim) {
            startAnim();
        } else {
            startThread();
        }
    }

    /*绘图*/
    public interface IRenderer {
        void onRender(Canvas canvas, long millisPassed);
    }

    private List<IRenderer> renderer;

    protected List<IRenderer> onCreateRenderer() {
        return null;
    }

    private void render(Canvas canvas, long millisPassed) {
        if (renderer != null) {
            for (int i = 0, size = renderer.size(); i < size; i++) {
                renderer.get(i).onRender(canvas, millisPassed);
            }
        } else {
            onRender(canvas, millisPassed);
        }
    }

    public void startAnim() {
        isStartAnim = true;
        startThread();
    }

    private static HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x000110, "GWaveLineView");

    private void startThread() {
        HiLog.info(label, "RV_startThread");
        if (renderThread != null && !renderThread.running) {
            renderThread.setRun(true);
            try {
                if (renderThread.getState() == Thread.State.NEW) {
                    HiLog.info(label, "RV_startThread01");
                    renderThread.start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private volatile boolean isStop = false;

    public void stopAnim() {
        HiLog.info(label, "RV_stopAnim:  1--> " + System.currentTimeMillis() + " : " + renderThread.running);
        isStartAnim = false;
        isStop = true;
        if (renderThread != null && renderThread.running) {
            renderThread.setRun(false);
            HiLog.info(label, "RV_stopAnim:  2--> " + System.currentTimeMillis());
            renderThread.interrupt();
            HiLog.info(label, "RV_stopAnim:  3--> " + System.currentTimeMillis());
        }
    }

    public boolean isRunning() {
        if (renderThread != null) {
            return renderThread.running;
        }
        return false;
    }

    //释放相关资源，防止内存泄漏
    public void release() {
        stopAnim();
        if (getSurfaceOps().get() != null && getSurfaceOps().get().getSurface() != null) {
            Surface surface = getSurfaceOps().get().getSurface();
            getSurfaceOps().get().removeCallback(this);
        }
    }

}
